package data;

import gui.MainPanel;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map.Entry;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;

public class Order {

	public enum OrderState {
		Unknown, New, Draft, Submitted, Accepted;

		public static OrderState getOrderState(String txt) {
			if (txt.equals("Nowe"))
				return OrderState.New;
			if (txt.equals("Kopia robocza"))
				return OrderState.Draft;
			if (txt.equals("Oczekuje na zatwierdzenie"))
				return OrderState.Submitted;
			if (txt.equals("Zatwierdzone"))
				return OrderState.Accepted;
			return OrderState.Unknown;
		}

		@Override
		public String toString() {
			switch (ordinal()) {
			case 1:
				return "Nowe";
			case 2:
				return "Kopia robocza";
			case 3:
				return "Oczekuje na zatwierdzenie";
			case 4:
				return "Zatwierdzone";
			default:
				return "Nieznane";
			}
		}

		public final static JsonDeserializer<OrderState> deserializer = new JsonDeserializer<Order.OrderState>() {

			@Override
			public OrderState deserialize(JsonElement json, Type arg1, JsonDeserializationContext context)
					throws JsonParseException {
				return OrderState.values()[json.getAsInt()];
			}
		};
	}

	private int mDbId;
	private String mNumber;
	private String mCostUnit;
	private Date mDate;
	private int mPaymentMethod;
	private OrderState mState;
	protected HashMap<DepartmentData, OrderDepartment> mOrderDepartments;
	//private int mApproverId;
	private String mUserLogin;
	private String mApproverLogin;
	private String mRejectReason;

	public Order(int dbId, String number, String costUnit, Date date, int paymentMethod, OrderState state,
			HashMap<DepartmentData, OrderDepartment> orderDepartments) {
		mDbId = dbId;
		mNumber = number;
		mCostUnit = costUnit;
		mDate = date;
		mPaymentMethod = paymentMethod;
		mState = state;
		mOrderDepartments = orderDepartments;
		//mApproverId = -1;
		mUserLogin = "";
		mApproverLogin = "";
		mRejectReason = "";
	}

	public Order(int dbId, String number, String costUnit, Date date, int paymentMethod, OrderState state,
			HashMap<DepartmentData, OrderDepartment> orderDepartments, /*int approverId,*/ String userLogin, 
			String approverLogin, String rejectReason) {
		mDbId = dbId;
		mNumber = number;
		mCostUnit = costUnit;
		mDate = date;
		mPaymentMethod = paymentMethod;
		mState = state;
		mOrderDepartments = orderDepartments;
		//mApproverId = approverId;
		mUserLogin = userLogin;
		mApproverLogin = approverLogin;
		mRejectReason = rejectReason;
	}

	public Order(Order order) {
		mDbId = order.mDbId;
		mNumber = order.mNumber;
		mCostUnit = order.mCostUnit;
		mDate = order.mDate;
		mPaymentMethod = order.mPaymentMethod;
		mState = order.mState;
		mOrderDepartments = order.mOrderDepartments;
		mUserLogin = order.mUserLogin;
		mApproverLogin = order.mApproverLogin;
		mRejectReason = order.mRejectReason;
	}

	public int getDbId() {
		return mDbId;
	}

	public void setDbId(int dbId) {
		mDbId = dbId;
	}

	public String getNumber() {
		return mNumber;
	}

	public String getCostUnit() {
		return mCostUnit;
	}

	public Date getDate() {
		return mDate;
	}

	public int getPaymentMethod() {
		return mPaymentMethod;
	}

	public OrderState getState() {
		return mState;
	}

	public void setState(OrderState state) {
		mState = state;
	}

	public HashMap<DepartmentData, OrderDepartment> getOrderDepartments() {
		return mOrderDepartments;
	}

	public String getUserLogin() {
		return mUserLogin;
	}
	
	public String getApproverLogin() {
		return mApproverLogin;
	}
	
	public String getRejectReason() {
		return mRejectReason;
	}

	public boolean validate() {
		return !mNumber.isEmpty() && !mCostUnit.isEmpty() && !mOrderDepartments.isEmpty();
	}

	public static final JsonDeserializer<Order> deserializer = new JsonDeserializer<Order>() {

		@Override
		public Order deserialize(JsonElement json, Type arg1, JsonDeserializationContext context)
				throws JsonParseException {

			int dbId = 0;
			try {
				dbId = json.getAsJsonObject().get("id").getAsInt();
			} catch (NullPointerException ex) {
				dbId = 0;
			}
			String number = json.getAsJsonObject().get("number").getAsString();
			String costUnit = json.getAsJsonObject().get("costUnit").getAsString();
			String dateStr = json.getAsJsonObject().get("date").getAsString();
			Date date = null;
			try {
				date = new SimpleDateFormat("yyyy-MM-DD").parse(dateStr);
			} catch (ParseException e) {
				date = null;
			}
			int paymentMethod = json.getAsJsonObject().get("paymentMethod").getAsInt();
			OrderState state = context.deserialize(json.getAsJsonObject().get("state"), OrderState.class);
			JsonObject jSubOrders = json.getAsJsonObject().get("orderDepartments").getAsJsonObject();
			HashMap<DepartmentData, OrderDepartment> subOrders = new HashMap<>();
			for (Entry<String, JsonElement> entry : jSubOrders.entrySet()) {
				if (entry.getValue().isJsonArray() && entry.getValue().getAsJsonArray().size() == 0)
					subOrders.put(MainPanel.getDepartmentByDbId(Integer.parseInt(entry.getKey())), null);
				else {
					OrderDepartment orderDepartment = (OrderDepartment) context.deserialize(entry.getValue()
							.getAsJsonObject(), OrderDepartment.class);
					subOrders.put(MainPanel.getDepartmentByDbId(Integer.parseInt(entry.getKey())), orderDepartment);
				}
			}
			//int approverId = json.getAsJsonObject().get("approverId").getAsInt();
			String userLogin = null;
			if (!json.getAsJsonObject().get("user_login").isJsonNull())
				userLogin = json.getAsJsonObject().get("user_login").getAsString();
			String approverLogin = null;
			if (!json.getAsJsonObject().get("approver_login").isJsonNull())
				approverLogin = json.getAsJsonObject().get("approver_login").getAsString();
			String rejectReason = null;
			if (!json.getAsJsonObject().get("reject_reason").isJsonNull())
				rejectReason = json.getAsJsonObject().get("reject_reason").getAsString();
			return new Order(dbId, number, costUnit, date, paymentMethod, state, subOrders, /*approverId,*/ userLogin, approverLogin, rejectReason);
		}
	};

	public static final JsonSerializer<Order> serializer = new JsonSerializer<Order>() {

		@Override
		public JsonElement serialize(Order arg0, Type arg1, JsonSerializationContext arg2) {
			JsonObject obj = new JsonObject();
			obj.addProperty("mDbId", arg0.getDbId());
			obj.addProperty("mNumber", arg0.getNumber());
			obj.addProperty("mCostUnit", arg0.getCostUnit());
			obj.addProperty("mDate", new SimpleDateFormat("yyyy-MM-dd").format(arg0.getDate()));
			obj.addProperty("mPaymentMethod", arg0.getPaymentMethod());
			obj.addProperty("mState", arg0.getState().ordinal());
			obj.add("mOrderDepartments", arg2.serialize(arg0.getOrderDepartments(),
					new TypeToken<HashMap<DepartmentData, OrderDepartment>>() {
					}.getType()));
			obj.addProperty("mRejectReason", arg0.getRejectReason());
			return obj;
		}
	};
}
